﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.BizTalk.Component.Interop;
using System.IO;
using System.Globalization;
using log4net;
using Microsoft.ApplicationInsights.DataContracts;
using AppFx.BizTalk.Diagnostics;

namespace AppFx.BizTalk.PipelineComponents
{
    /// <summary>
    /// Pipeline component which can log and hide exception details on the response side of a request response port so detailed exceptions wouldnt be thrown and expose a security risk
    /// </summary>
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [System.Runtime.InteropServices.Guid(ComponentGuid)]
    public class MessageIn : BaseCustomPipelineComponent, IComponent, IComponentUI, IPersistPropertyBag
    {
        private static readonly ILog Log = LogFactory.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private const string ComponentGuid = "13542D09-8229-42A6-A043-57B7D7DC75F3";
        private const string ComponentDescription = "Logs a message in";
        private const string ComponentName = "MessageIn";
                
        /// <summary>
        /// Ctor
        /// </summary>
        public MessageIn()
            : base(ComponentName, typeof(ResponseExceptionHiding), ComponentDescription)
        {

        }

        #region IComponent Members
        /// <summary>
        /// Processing of the component
        /// </summary>
        /// <param name="pContext"></param>
        /// <param name="pInMsg"></param>
        /// <returns></returns>
        public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
        {            
            if (pInMsg == null)
                throw new ArgumentNullException("pInMsg");

            //Properties
            var messageType = GetMessageType(pInMsg);
            var messageId = pInMsg.MessageID.ToString();

            //Log to Log4net
            Log.DebugFormat("Message In: {0} - {1}", messageType, messageId);

            //Log to App Insights
            if (TelemetryEnabled)
            {
                var telemetryClient = Diagnostics.Telemetry.TelemetryManager.GetNamedClient(TelemetryClientName, true);
                if (telemetryClient != null)
                {
                    var telemetryEvent = new EventTelemetry(string.Format("BTS-MessageIn: {0}", messageType));
                    telemetryEvent.Properties.Add(new KeyValuePair<string, string>("BizTalk-MessageID", pInMsg.MessageID.ToString()));
                    telemetryClient.TrackEvent(telemetryEvent);
                }
            }

            return pInMsg;
        }
        #endregion
       
        private string GetMessageType(Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
        {
            var messageTypeProperty = new BTS.MessageType();
            var messageType = (string)pInMsg.Context.Read(messageTypeProperty.Name.Name, messageTypeProperty.Name.Namespace);
            return messageType;
        }

        #region Properties
        private string _telemetryClientName;
        private bool _telemetryEnabled;

        public bool TelemetryEnabled
        {
            get { return _telemetryEnabled; }
            set { _telemetryEnabled = value; }
        }

        public string TelemetryClientName
        {
            get { return _telemetryClientName; }
            set { _telemetryClientName = value; }
        }
        
        #endregion

        #region IComponentUI Members
        /// <summary>
        /// Icon
        /// </summary>
        public IntPtr Icon
        {
            get { return IntPtr.Zero; }
        }
        /// <summary>
        /// Validate
        /// </summary>
        /// <param name="projectSystem"></param>
        /// <returns></returns>
        public System.Collections.IEnumerator Validate(object projectSystem)
        {
            return null;
        }
        #endregion

        #region IPersistPropertyBag Members
        /// <summary>
        /// The guid
        /// </summary>
        /// <param name="classID"></param>
        public void GetClassID(out Guid classID)
        {
            classID = new Guid(ComponentGuid);
        }
        /// <summary>
        /// No implementation
        /// </summary>
        public void InitNew()
        {
        }
        /// <summary>
        /// Loads from property bag
        /// </summary>
        /// <param name="propertyBag"></param>
        /// <param name="errorLog"></param>        
        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            try
            {
                base.ReadPropertyBag(propertyBag, "TelemetryClientName", ref _telemetryClientName);
                base.ReadPropertyBagAsBool(propertyBag, "TelemetryEnabled", ref _telemetryEnabled);             
            }
            catch (Exception ex)
            {
                string message = string.Format(CultureInfo.InvariantCulture, "IPersistPropertyBag.Load error: {0}", ex.ToString());
                Log.Error(message, ex);
                throw;
            }
        }
        /// <summary>
        /// Sdaves state to property bag
        /// </summary>
        /// <param name="propertyBag"></param>
        /// <param name="clearDirty"></param>
        /// <param name="saveAllProperties"></param>
        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            try
            {
                base.WritePropertyBag(propertyBag, "TelemetryClientName", _telemetryClientName);
                base.WritePropertyBag(propertyBag, "TelemetryEnabled", _telemetryEnabled);                
            }
            catch (Exception ex)
            {
                string message = string.Format(CultureInfo.InvariantCulture, "IPersistPropertyBag.Load error: {0}", ex.ToString());
                Log.Error(message, ex);
                throw;
            }
        }
        #endregion
    }
}

